'    Copyright 2008 Jan Molnar <jan.molnar@abds.de>
'
'    This file is part of JCQ.

'    JCQ is free software: you can redistribute it and/or modify
'    it under the terms of the GNU General Public License as published by
'    the Free Software Foundation, either version 2 of the License, or
'    (at your option) any later version.

'    JCQ is distributed in the hope that it will be useful,
'    but WITHOUT ANY WARRANTY; without even the implied warranty of
'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'    GNU General Public License for more details.

'    You should have received a copy of the GNU General Public License
'    along with JCQ. If not, see <http://www.gnu.org/licenses/>.

Public Class ByteConverter
    Private Shared ReadOnly _unixfsd As System.DateTime = New System.DateTime(1970, 1, 1, 0, 0, 0)
    Private Shared ReadOnly _icqenc As System.Text.Encoding = System.Text.Encoding.GetEncoding(28599)

    Public Shared Function GetBytes(ByVal value As UInt16) As Byte()
        Dim bytes As Byte() = BitConverter.GetBytes(value)
        Array.Reverse(bytes)
        Return bytes
    End Function

    Public Shared Function GetBytes(ByVal value As UInt32) As Byte()
        Dim bytes As Byte() = BitConverter.GetBytes(value)
        Array.Reverse(bytes)
        Return bytes
    End Function

    Public Shared Function GetBytes(ByVal value As UInt64) As Byte()
        Dim bytes As Byte() = BitConverter.GetBytes(value)
        Array.Reverse(bytes)
        Return bytes
    End Function

    Public Shared Function GetBytesLE(ByVal value As UInt16) As Byte()
        Return BitConverter.GetBytes(value)
    End Function

    Public Shared Function GetBytesLE(ByVal value As UInt32) As Byte()
        Return BitConverter.GetBytes(value)
    End Function

    Public Shared Function GetBytesLE(ByVal value As UInt64) As Byte()
        Return BitConverter.GetBytes(value)
    End Function

    Public Shared Function GetBytes(ByVal value As String) As Byte()
        Dim bytes As Byte() = _icqenc.GetBytes(value)
        Return bytes
    End Function

    Public Shared Function GetBytes(ByVal value As System.Guid) As Byte()
        Dim bGuidNet(15) As System.Byte
        Dim bGuidIcq(15) As System.Byte

        bGuidNet = value.ToByteArray

        bGuidIcq(0) = bGuidNet(3)
        bGuidIcq(1) = bGuidNet(2)
        bGuidIcq(2) = bGuidNet(1)
        bGuidIcq(3) = bGuidNet(0)

        bGuidIcq(4) = bGuidNet(5)
        bGuidIcq(5) = bGuidNet(4)

        bGuidIcq(6) = bGuidNet(7)
        bGuidIcq(7) = bGuidNet(6)

        bGuidIcq(8) = bGuidNet(8)
        bGuidIcq(9) = bGuidNet(9)

        bGuidIcq(6) = bGuidNet(7)
        bGuidIcq(7) = bGuidNet(6)

        bGuidIcq(10) = bGuidNet(10)
        bGuidIcq(11) = bGuidNet(11)
        bGuidIcq(12) = bGuidNet(12)
        bGuidIcq(13) = bGuidNet(13)
        bGuidIcq(14) = bGuidNet(14)
        bGuidIcq(15) = bGuidNet(15)

        Return bGuidIcq
    End Function

    'Public Shared Function GetBytes(ByVal value As Date) As Byte()
    '    Dim lngSeconds As UInt32

    '    If value < _unixfsd Then
    '        lngSeconds = 0
    '    Else
    '        lngSeconds = Convert.ToUInt32(value.Subtract(_unixfsd).TotalSeconds)
    '    End If

    '    Return GetBytes(lngSeconds)
    'End Function

    Public Shared Function GetBytesForUInt32Date(ByVal value As Date) As Byte()
        Dim lngSeconds As UInt32

        If value < _unixfsd Then
            lngSeconds = 0
        Else
            lngSeconds = Convert.ToUInt32(value.Subtract(_unixfsd).TotalSeconds)
        End If

        Return GetBytes(lngSeconds)
    End Function

    Public Shared Function GetBytesForUInt64Date(ByVal value As Date) As Byte()
        Dim lngSeconds As UInt64

        If value < _unixfsd Then
            lngSeconds = 0
        Else
            lngSeconds = Convert.ToUInt64(value.Subtract(_unixfsd).TotalSeconds)
        End If

        Return GetBytes(lngSeconds)
    End Function

    Public Shared Function GetBytesForStringWithLeadingByteLength(ByVal value As String) As Byte()
        Dim list As List(Of Byte)

        If String.IsNullOrEmpty(value) Then
            Return New Byte() {0}
        Else
            list = New List(Of Byte)
            list.Add(Convert.ToByte(value.Length))
            list.AddRange(GetBytes(value))

            Return list.ToArray
        End If
    End Function

    Public Shared Function GetBytesForStringWithLeadingUInt16Length(ByVal value As String) As Byte()
        Dim list As List(Of Byte)

        If String.IsNullOrEmpty(value) Then
            Return New Byte() {0}
        Else
            list = New List(Of Byte)
            list.AddRange(ByteConverter.GetBytes(Convert.ToUInt16(value.Length)))
            list.AddRange(GetBytes(value))

            Return list.ToArray
        End If
    End Function

    Public Shared Function GetBytesForStringWithLeadingUInt32Length(ByVal value As String) As Byte()
        Dim list As List(Of Byte)

        If String.IsNullOrEmpty(value) Then
            Return New Byte() {0}
        Else
            list = New List(Of Byte)
            list.AddRange(ByteConverter.GetBytes(Convert.ToUInt32(value.Length)))
            list.AddRange(GetBytes(value))

            Return list.ToArray
        End If
    End Function

    Public Shared Function GetXorHashFromPassword(ByVal pwd As Char()) As List(Of Byte)
        Dim plainText As List(Of System.Byte)
        Dim roast() As System.Byte = New System.Byte() {&HF3, &H26, &H81, &HC4, &H39, &H86, &HDB, &H92, &H71, &HA3, &HB9, &HE6, &H53, &H7A, &H95, &H7C}
        Dim xoredPassword As List(Of System.Byte)
        Dim xorIndex As Integer

        plainText = New List(Of System.Byte)(System.Text.Encoding.GetEncoding(28599).GetBytes(pwd))
        xoredPassword = New List(Of System.Byte)

        For i As Integer = 0 To plainText.Count - 1
            xoredPassword.Add(roast(xorIndex) Xor plainText(i))

            If xorIndex = roast.Length - 1 Then
                xorIndex = 0
            Else
                xorIndex += 1
            End If
        Next

        Return xoredPassword
    End Function

    Public Shared Function ToGuid(ByVal value As IEnumerable(Of Byte)) As Guid
        Dim bytes As List(Of Byte) = New List(Of Byte)(value)
        Dim bGuid(15) As Byte

        bGuid(3) = bytes(0)
        bGuid(2) = bytes(1)
        bGuid(1) = bytes(2)
        bGuid(0) = bytes(3)
        bGuid(5) = bytes(4)
        bGuid(4) = bytes(5)
        bGuid(7) = bytes(6)
        bGuid(6) = bytes(7)
        bGuid(8) = bytes(8)
        bGuid(9) = bytes(9)
        bGuid(10) = bytes(10)
        bGuid(11) = bytes(11)
        bGuid(12) = bytes(12)
        bGuid(13) = bytes(13)
        bGuid(14) = bytes(14)
        bGuid(15) = bytes(15)

        Return New Guid(bGuid)
    End Function

    Public Shared Function ToUInt16(ByVal value As IEnumerable(Of Byte)) As UInt16
        Dim bytes As List(Of Byte) = New List(Of Byte)(value)
        bytes.Reverse()
        Return BitConverter.ToUInt16(bytes.ToArray, 0)
    End Function

    Public Shared Function ToUInt32(ByVal value As IEnumerable(Of Byte)) As UInt32
        Dim bytes As List(Of Byte) = New List(Of Byte)(value)
        bytes.Reverse()
        Return BitConverter.ToUInt32(bytes.ToArray, 0)
    End Function

    Public Shared Function ToUInt64(ByVal value As IEnumerable(Of Byte)) As UInt64
        Dim bytes As List(Of Byte) = New List(Of Byte)(value)
        bytes.Reverse()
        Return BitConverter.ToUInt64(bytes.ToArray, 0)
    End Function

    Public Shared Function ToUInt16LE(ByVal value As IEnumerable(Of Byte)) As UInt16
        Dim bytes As List(Of Byte) = New List(Of Byte)(value)
        Return BitConverter.ToUInt16(bytes.ToArray, 0)
    End Function

    Public Shared Function ToUInt32LE(ByVal value As IEnumerable(Of Byte)) As UInt32
        Dim bytes As List(Of Byte) = New List(Of Byte)(value)
        Return BitConverter.ToUInt32(bytes.ToArray, 0)
    End Function

    Public Shared Function ToUInt64LE(ByVal value As IEnumerable(Of Byte)) As UInt64
        Dim bytes As List(Of Byte) = New List(Of Byte)(value)
        Return BitConverter.ToUInt64(bytes.ToArray, 0)
    End Function

    Public Shared Function ToDateTimeFromUInt32FileStamp(ByVal bytes As System.Collections.Generic.List(Of Byte)) As DateTime
        Dim lngSeconds As Long

        lngSeconds = ToUInt32(bytes.GetRange(0, 4))

        Return _unixfsd.AddSeconds(lngSeconds)
    End Function

    Public Shared Function ToDateTimeFromUInt64FileStamp(ByVal bytes As System.Collections.Generic.List(Of Byte)) As DateTime
        Dim lngSeconds As Decimal

        lngSeconds = ToUInt64(bytes.GetRange(0, 8))

        Return _unixfsd.AddSeconds(lngSeconds)
    End Function

    Public Shared Function ToHex(ByVal value As Integer) As String
        Return String.Format("{0:X2}", value)
    End Function

    Public Shared Function ToStringFromByteIndex(ByVal index As Integer, ByVal data As List(Of Byte)) As String
        Dim length As Byte
        Dim text As String

        length = data(index)

        'If data.Count < index + length Then Throw New NotEnoughBytesException("Text", data.Count, index + length)

        text = ToString(data.GetRange(index + 1, length))

        Return text
    End Function

    Public Shared Function ToStringFromUInt16Index(ByVal index As Integer, ByVal data As System.Collections.Generic.List(Of Byte)) As String
        Dim length As Integer
        Dim text As String

        length = ToUInt16(data.GetRange(index, 2))

        'If data.Count < index + length Then Throw New NotEnoughBytesException("Text", data.Count, index + length)

        text = ToString(data.GetRange(index + 2, length))

        Return text
    End Function

    Public Shared Function ToStringFromUInt16LEIndex(ByVal index As Integer, ByVal data As System.Collections.Generic.List(Of Byte)) As String
        Dim length As Integer
        Dim text As String

        length = ToUInt16LE(data.GetRange(index, 2))

        'If data.Count < index + length Then Throw New NotEnoughBytesException("Text", data.Count, index + length)

        text = ToString(data.GetRange(index + 2, length))

        Return text
    End Function

    Public Shared Function ToZeroBasedStringFromUInt16LEIndex(ByVal index As Integer, ByVal data As System.Collections.Generic.List(Of Byte)) As String
        Dim length As Integer
        Dim text As String

        length = ToUInt16LE(data.GetRange(index, 2))

        text = ToString(data.GetRange(index + 2, length - 1))

        Return text
    End Function

    Public Overloads Shared Function ToString(ByVal bytes As List(Of Byte)) As String
        Return _icqenc.GetString(bytes.ToArray)
    End Function
End Class